/**
 * 偏移量工具
 */
function sOffsetUtil(){
    /**
     * 偏移量常用属性
     */
    var offsetProps = [
        "pageIndex",
        "rowIndex",
        "elementIndex",
        "contentIndex",
        "absoluteIndex",
        "startPageIndex",
        "endPageIndex",
        "startRowIndex",
        "endRowIndex",
        "tableRowIndex",
        "tableColIndex",
        "start",
        "end"
    ];

    /**
     * 从目标中抽取偏移量
     * @param {*} target 目标
     * @param {*} deep true 只抽取最深层的偏移量
     * @returns 
     */
    this.extractOffset = function(target, deep){
        var offset = {};
        var name = null;

        for(var i in offsetProps){
            name = offsetProps[i];
            if(target[name] == null) continue;
            
            offset[name] = target[name];
        }

        var next = target.next;
        if(deep){
            while(next){
                if(!next.next){
                    offset = {...next};
                }
                next = next.next;
            }
        }else{
            var prev = offset;
            while(next){
                prev.next = {...next};
                prev = prev.next;
                next = next.next;
            }
        }

        return offset;
    }

    /**
     * 从目标中抽取偏移量,并以数组形式返回
     * @param {*} target 目标
     * @returns 
     */
    this.splitOffset = function(target){
        var arr = [];
        var offset = {};
        var name = null;

        for(var i in offsetProps){
            name = offsetProps[i];
            if(target[name] == null) continue;
            
            offset[name] = target[name];
        }
        
        arr.push(offset);

        var next = target.next;
        while(next){
            let n = {...next};
            delete n.next;

            arr.push(n);
            
            next = next.next;
        }

        return arr;
    }

    /**
     * 组合偏移量
     * @param {*} arr 
     * @param {*} start 
     * @param {*} end 
     */
    this.concatOffset = function(arr, start, end){
        let offset = null;
        let next = null;

        for(let i = start; i <= end; i++){
            if(!offset){
                offset = {...arr[i]};
                next = offset;
            }else{
                next.next = {...arr[i]};
                next = next.next;
            }
        }

        return offset;
    }

    /**
     * 从目标中抽取第一层偏移量
     * @param {*} target
     * @returns 
     */
    this.extractShallowOffset = function(target){
        return {
            pageIndex: target.pageIndex,
            rowIndex: target.rowIndex,
            elementIndex: target.elementIndex,
            contentIndex: target.contentIndex
        };
    }

    /**
     * 从偏移量中抽取最深层单元格的偏移量
     * @param {*} offset 偏移量
     * @param {*} table 指定表格
     * @returns 
     */
    this.extractCellOffset = function(offset, table){
        var cellOffset = {
            pageIndex: offset.pageIndex,
            rowIndex: offset.rowIndex,
            elementIndex: offset.elementIndex,
        };

        var next = cellOffset;
        var flg = false;

        for(var n = offset.next; n != null; n = n.next){
            if(n.next){
                next.next = {...n};

                if(table && n.table === table){
                    next.next = {
                        tableRowIndex: next.next.tableRowIndex,
                        tableColIndex: next.next.tableColIndex
                    };

                    flg = true;
                }

                next = next.next;
                delete next.next;
            }else{
                next.next = {
                    tableRowIndex: n.tableRowIndex,
                    tableColIndex: n.tableColIndex
                }
            }

            if(flg){
                break;
            }
        }

        return cellOffset;
    }

    /**
     * 按层级从偏移量中抽取单元格的偏移量
     * @param {*} offset 偏移量
     * @param {*} level 层级
     * @returns 
     */
    this.extractCellOffsetByLevel = function(offset, level){
        var cellOffset = {
            pageIndex: offset.pageIndex,
            rowIndex: offset.rowIndex,
            elementIndex: offset.elementIndex,
        };

        var next = cellOffset;
        var count = 1;
        
        for(var n = offset.next; n != null; n = n.next){
            if(count == level){
                next.next = {
                    tableRowIndex: n.tableRowIndex,
                    tableColIndex: n.tableColIndex
                }
                break;
            }else{
                next.next = {...n};
                next = next.next;
            }

            count++;
        }

        return cellOffset;
    }

    /**
     * 抽取倒数第二层偏移量，没有返回第一层
     */
    this.extractLastNextPrevOffset = function(offset){
        var prev = null;
        for(var next = offset; next != null; next = next.next){
            if(next.next != null){
                prev = next;
            }
        }

        if(prev){
            prev = {...prev};
        }else{
            prev = {...offset};
        }

        delete prev.next;

        return prev;
    }

    /**
     * 将偏移量进行合并
     * @param {*} offset 被合并偏移量
     * @param {*} mOffset 合并偏移量
     */
    this.mergeOffsetNext = function(offset, mOffset){
        if(!offset.next) {
            for(var i in mOffset){
                offset[i] = mOffset[i];
            }
            return offset;
        }

        for(var n = offset; n != null; n = n.next){
            if(!n.next.next) {
                n.next = {...n.next, ...mOffset};
                break;
            };
        }

        return offset;
    }

    /**
     * 将偏移量合并到目标
     * @param {*} target 
     * @param {*} offset 
     */
    this.mergeOffset = function(target, offset){
        var t = target;
        for(var next = offset; next != null; next = next.next){
            for(var i in next){
                if(i == "next") continue;
                t[i] = next[i];
            }
            if(next.next){
                t.next = t.next ? t.next : {};
                t = t.next;
            }
        }
    }

    /**
     * 将偏移量最后一个next属性删除
     * @param {*} offset 
     */
    this.trimLastNext = function(offset){
        for(var next = offset; next != null; next = next.next){
            if(next.next){
                if(next.next.next == null){
                    delete next.next;
                }
            }
        }
        return offset;
    }

    /**
     * 更新偏移量的页码, 排除最后一层
     * @param {*} offset 
     * @param {*} pageIndex 
     */
    this.updatePageIndexExceptLastNext = function(offset, pageIndex){
        for(var next = offset; next != null; next = next.next){
            if(next.next != null){
                next.pageIndex = pageIndex;
                next.rowIndex = 1;
                next.elementIndex = 0;
            }
        }
    }

    /**
     * 更新页码和行号
     * @param {*} offset 
     * @param {*} pageIndex 
     * @param {*} rowIndex
     */
    this.updatePageWithRowIndex = function(offset, pageIndex, rowIndex){
        for(var next = offset; next != null; next = next.next){
            if(pageIndex != null){
                next.pageIndex = pageIndex;
            }
            if(rowIndex != null){
                next.rowIndex = rowIndex;
            }
        }
    }

    /**
     * 将内容序号加1
     * @param {*} offset 
     * @param {*} step
     * @returns offset
     */
    this.plusContentIndex = function(offset, step){
        for(var next = offset; next != null; next = next.next){
            if(!next.next){
                next.contentIndex += step != null ? step : 1;
            }
        }

        return offset;
    }

    /**
     * 将元素序号加1
     * @param {*} offset 
     * @param {*} step
     * @returns offset
     */
    this.plusElementIndex = function(offset, step){
        for(var next = offset; next != null; next = next.next){
            if(!next.next){
                next.elementIndex += step != null ? step : 1;
            }
        }

        return offset;
    }

    /**
     * 更新最深层偏移量的内容序号
     * @param {*} offset 
     * @param {*} plus 
     * @param {*} contentIndex 
     * @returns 
     */
    this.updateContentIndexForNext = function(offset, plus, contentIndex){
        for(var next = offset; next != null; next = next.next){
            if(next.next) continue;
            if(contentIndex != null){
                next.contentIndex = contentIndex;
            }else{
                next.contentIndex += plus ? 1 : -1;
            }
            break;
        }
        return next.contentIndex;
    }

    /**
     * 判断指定偏移量是否在开始和结束偏移量之间
     * @param {*} startOffset 开始偏移量
     * @param {*} endOffset 结束便宜朗
     * @param {*} offset 指定偏移量
     */
    this.amongOffset = function(startOffset, endOffset, offset){
        let next = offset;

        for(let it = startOffset; it != null; it = it.next){
            if(next.tableRowIndex != null){
                if(next.tableRowIndex < it.tableRowIndex) return false;
                if(next.tableRowIndex == it.tableRowIndex && 
                    next.tableColIndex < it.tableColIndex) return false;
                continue;
            }
            if(next.pageIndex < it.pageIndex) return false;
            if(next.pageIndex == it.pageIndex && next.rowIndex < it.rowIndex) return false;
            if(next.pageIndex == it.pageIndex && next.rowIndex == it.rowIndex && 
                next.elementIndex < it.elementIndex) return false;
            if(next.pageIndex == it.pageIndex && next.rowIndex == it.rowIndex && 
                next.elementIndex == it.elementIndex && next.contentIndex < it.contentIndex) return false;

            next = next.next;
            if(!next) break;
        }

        next = offset;

        for(let it = endOffset; it != null; it = it.next){
            if(next.tableRowIndex != null){
                if(next.tableRowIndex > it.tableRowIndex) return false;
                if(next.tableRowIndex == it.tableRowIndex && 
                    next.tableColIndex > it.tableColIndex) return false;
                continue;
            }
            if(next.pageIndex > it.pageIndex) return false;
            if(next.pageIndex == it.pageIndex && next.rowIndex > it.rowIndex) return false;
            if(next.pageIndex == it.pageIndex && next.rowIndex == it.rowIndex && 
                next.elementIndex > it.elementIndex) return false;
            if(next.pageIndex == it.pageIndex && next.rowIndex == it.rowIndex && 
                next.elementIndex == it.elementIndex && next.contentIndex > it.contentIndex) return false;

            next = next.next;
            if(!next) break;
        }

        return true;
    }

    /**
     * 更新next属性
     * @param {*} offset 
     * @param {*} updateProps 
     */
    this.updateNext = function(offset, updateProps){
        for(var next = offset; next != null; next = next.next){
            if(next.next) continue;
            for(let i in updateProps){
                next[i] = updateProps[i];
            }
        }
        return offset;
    }
}